JS - werken met objecten
Doelstelling
Na deze les weet je dat:
- een object bestaat uit een verzameling eigenschappen;
- een eigenschap is een koppeling tussen een naam (of sleutel) en een waarde;
- de waarde van een eigenschap kan een primitief gegevenstype zijn, Number, Boolean, String, ...
- vermits functies 'first class citizen' zijn, namelijk functies zijn data, een eigenschap die gekoppeld is aan een functie een methode is;
- er naast objecten die vooraf zijn gedefinieerd zijn, ook zelfgemaakte objecten bestaan;
- hoe je met eigenschappen, functies en methoden je eigen objecten kunt maken;
- Overzicht van de doelstellingen:
Stappenplan
- Overzicht
- We vertrekken van de oefening uit OO programmeren in C# en we maken de Studentklasse in JS. Heb je nog geen kennis van C#, kan je de vergelijking met C# negeren:
- Deze klasse heeft 6 eigenschappen:
Name
(string)Age
(byte)ClassGroup
(maak hiervoor eenenum
ClassGroups
)MarkCommunication
(byte)MarkProgrammingPrinciples
(byte)MarkWebTech
(byte)
- Leeftijd en de punten stel je voor met full properties.
- Een student kan nooit ouder zijn dan 120.
- Je kan ook nooit een negatief cijfer of een cijfer boven 20 behalen.
- Voeg aan de klasse een read-only property
OverallMark
toe. Deze berekent het gemiddelde van de 3 punten als double. - Voeg aan de klasse ook de methode
ShowOverview()
toe. Deze methode zal een volledig rapport van de student tonen (inclusief het gemiddelde m.b.v. deOverallMark
-property). - Test je programma door enkele studenten aan te maken en in te stellen.
- Deze klasse heeft 6 eigenschappen:
- Een
enum
is een gegevenstype dat gebruikt wordt voor een opsomming van gelijkaardige elementen. Bijvoorbeeld de dagen van de week. De klassengroep in deStudent
klasse bevat een lijst van klassengroepen, namelijk EA1, EA2, EA3. JavaScript beschikt niet overenum
zoals C#. Daar passen we een mouw aan en we gebruiken een eenvoudigobject
om eenenum
voor te stellen. En object is tenslotte een lijst van eigenschappen die een koppeling legt tussen een sleutel en een waarde. Hier in dat geval is de sleutel gelijk aan de waarde:// in JavaScript bestaan er geen enums. // we gaan een enum nabootsen door gebruik // te maken van een object // vermits we dat object nooit gaan wijzigen // declareren we het als een const const classGroups = { EA1: 'EA1', EA2: "EA2", EA3: "EA3" };
We maken hier een literal object, een letterlijk object. We gebruiken geen OO syntaxis maar een soort van template: een door komma's gescheiden lijst van sleutel-waardeparen die tussen accolades staan. Object literals kapselen gegevens in, in een mooi afgebakend pakket.
-
const
Het object hierboven hebben we als const gedeclareerd. De lijst van klassengroepen stoppen we in een constante omdat de klassengroepen van te voren vast liggen en door het programma nooit zullen en mogen gewijzigd worden. -
We gaan onze eerste student als een object literal aanmaken:
let student1 = { name: 'Bob Dylan', age: 54, classGroup: classGroups.EA2, markCommunication: 18, markProgrammingPrinciples: 20, markWebTechnology: 19, overallMark: function() {return (this.markCommunication + this.markProgrammingPrinciples + this.markWebTechnology) / 3;}, showOverview: function () { return `Overzicht rapport: Naam: ${this.name} Klasgroep: ${this.classGroup} Leeftijd: ${this.age} Punten Communicatie: ${this.markCommunication} PP: ${this.markProgrammingPrinciples} WebTechnolgy: ${this.markWebTechnology} Gemiddelde: ${this.overallMark()}`; } }; console.log(student1.showOverview());
Hier zien we een paar interessante dingen. We hebben een reeks eigenschappen die enkele kenmerken van een student beschrijft, o.a. leeftijd, punten voor verschillende vakken, de naam. Maar er staan twee bijzondere eigenschappen in, namelijk
overallMark
enshowOverview
. Aan die twee sleutels worden ook data gekoppeld maar 't is wel speciale data, het zijn namelijk functies. En dat is niet meer zo eigenaardig als we in ons achterhoofd houden dat functies in JavaScript First citizen's zijn, namelijk data net zoalsNumber
enString
. Die twee eigenschappen worden dan geen eigenshappen meer genoemd maar methoden. -
let
Het object Student hebben we met let gedeclareerd. Student is geenconst
omdat de waarden ervan tijdens het verloop van het programma gewijzigd kunnen worden. Alle variabelen declareer je metlet
ofconst
. - Stringinterpolatie met de backtick `
Je kan JavaScript code binnenin een string gebruiken als je de string tussen twee backticks plaatst. De JavaScript code plaats je tussen accolades en je zet er een $ teken voor. Let erop dat je de string ook over meer dan één lijn kan schrijven. Dat laat je toe de string formatteren:
return `Overzicht rapport: Naam: ${this.name} Klasgroep: ${this.classGroup} Leeftijd: ${this.age} Punten Communicatie: ${this.markCommunication} PP: ${this.markProgrammingPrinciples} WebTechnolgy: ${this.markWebTechnology} Gemiddelde: ${this.overallMark()}`
De spaties en de nieuwe regels (new line) zullen op het scherm getoond worden. Je hoeft dus geen escape sign (\n) gebruiken om aan te geven dat je naar de volgende lijn wil gaan op het scherm.
In JavaScript spreekt men van Template literals of Template strings.
-
this
Met het sleutelwoord this kan je binnen een methode verwijzen naar andere eigenschappen in het huidige object. Dit gebruiken bv in de anonieme functie die in overallMark zit:(this.markCommunication + this.markProgrammingPrinciples + this.markWebTechnology) / 3;
-
Anonieme functies
In hetStudent
object hierboven hebben we een functies toegekend aan de eigenschappenoverallMark
enshowOverview
. Deze functies hebben geen naam en daarom spreekt men van anonieme functies of functies zonder naam. Waarom doen we dat. Wel eerlijk gezegd een beetje uit luiheid. Ik heb geen zin om eerste een functie met een naam te schrijven en dan die naam toe te kennen aan de eigenschap. Het gaat veel sneller om een anonieme functie ter plekke te schrijven en zonder omwegen in die eigenschap te proppen. Dus hier zie je wat een anonieme functie betekent en ook een voorbeeld waarom je zo'n ding in bepaalde omstandigheden nuttig kan zijn. -
Eventueel probleem met anonieme functies
We maken nog eenStudent object literal
:let student2 = { name: 'Sareh El Farisi', age: 24, classGroup: classGroups.EA3, markCommunication: 19, markProgrammingPrinciples: 20, markWebTechnology: 19, overallMark: function() {return (this.markCommunication + this.markProgrammingPrinciples + this.markWebTechnology) / 3; }, showOverview: function () { return `Overzicht rapport: Naam: ${this.name} Klasgroep: ${this.classGroup} Leeftijd: ${this.age}`;} };
Ik heb nu twee studenten met elk twee dezelfde anonieme functies. Als er nog een paar studenten bij komen ga ik mijn luiheid van daarstraks duur betalen. Ik moet voor elke student die anonieme functies intypen. En veronderstel dat er iets in één van die anonieme functies gewijzigd moet worden. Dan moet ik dat op evenzoveel plaatsen wijzigen als dat er studenten zijn.
-
Functies met een naam of named functions
Ik schrijf nu twee functies met een naam:function showOverview() { return `Overzicht rapport (met een named function): Naam: ${this.name} Klasgroep: ${this.classGroup} Leeftijd: ${this.age} Punten Communicatie: ${this.markCommunication} PP: ${this.markProgrammingPrinciples} WebTechnolgy: ${this.markWebTechnology} Gemiddelde: ${this.overallMark()}`; } function overallMark() { return (this.markCommunication + this.markProgrammingPrinciples + this.markWebTechnology) / 3; }
En we overschrijven de methode eigenschappen in de twee Student objecten:
// we kunnen een eigenschap met een nieuwe waarde overschrijven // hier overschrijven we de anonieme functie met een functie met een naam student1.overallMark = overallMark; student1.showOverview = showOverview; console.log(student1.showOverview()) student2.overallMark = overallMark; student2.showOverview = showOverview; console.log(student2.showOverview())
Als we één van de functies willen wijzigen moeten we dat maar op één plaats doen, namelijk in de desbetreffende named function. Neem aan dat we de naam van de student in hoofdletters willen tonen dan wijzigen we de functie met de naam
showOvervieuw
als volgt:function showOverview() { return `Overzicht rapport (met een named function): Naam: ${this.name.toUpperCase()} Klasgroep: ${this.classGroup} Leeftijd: ${this.age} Punten Communicatie: ${this.markCommunication} PP: ${this.markProgrammingPrinciples} WebTechnolgy: ${this.markWebTechnology} Gemiddelde: ${this.overallMark()}`; }
Op één plaats de code wijzigen, en alle namen van de studenten worden in hoofdletter getoond!
-
Alles is nog niet niet gezegd over werken met objecten. In een volgende les leren we:
-
objecten maken met de
new Object()
constructor; - werken met arrays van object;
- werken met de
forEach
,map
,reduce
enfilder
functies van array's - Encapsulatie met het function object;
-
Code
Hier volgt de volledige code. Plaats het in een bestand met de naam werken-met-objecten1.js:
// in JavaScript bestaan er geen enums. // we gaan een enum nabootsen door gebruik // te maken van een object // vermits we dat object nooit gaan wijzigen // declareren we het als een const const classGroups = { EA1: 'EA1', EA2: "EA2", EA3: "EA3" }; function showOverview() { return `Overzicht rapport (met een named function): Naam: ${this.name.toUpperCase()} Klasgroep: ${this.classGroup} Leeftijd: ${this.age} Punten Communicatie: ${this.markCommunication} PP: ${this.markProgrammingPrinciples} WebTechnolgy: ${this.markWebTechnology} Gemiddelde: ${this.overallMark()}`; } function overallMark() { return (this.markCommunication + this.markProgrammingPrinciples + this.markWebTechnology) / 3; } let student1 = { name: 'Bob Dylan', age: 54, classGroup: classGroups.EA2, markCommunication: 18, markProgrammingPrinciples: 16, markWebTechnology: 12, overallMark: function() {return (this.markCommunication + this.markProgrammingPrinciples + this.markWebTechnology) / 3;}, showOverview: function () { return `Overzicht rapport: Naam: ${this.name} Klasgroep: ${this.classGroup} Leeftijd: ${this.age} Punten Communicatie: ${this.markCommunication} PP: ${this.markProgrammingPrinciples} WebTechnolgy: ${this.markWebTechnology} Gemiddelde: ${this.overallMark()}`; } }; console.log(student1.showOverview()); let student2 = { name: 'Sareh El Farisi', age: 54, classGroup: classGroups.EA2, markCommunication: 18, markProgrammingPrinciples: 20, markWebTechnology: 19, overallMark: function() {return (this.markCommunication + this.markProgrammingPrinciples + this.markWebTechnology) / 3;}, showOverview: function () { return `Overzicht rapport: Naam: ${this.name} Klasgroep: ${this.classGroup} Leeftijd: ${this.age} Punten Communicatie: ${this.markCommunication} PP: ${this.markProgrammingPrinciples} WebTechnolgy: ${this.markWebTechnology} Gemiddelde: ${this.overallMark()}`; } }; console.log(student2.showOverview()); // we kunnen een eigenschap met een nieuwe waarde overschrijven // hier overschrijven we de anonieme functie met een functie met een naam student1.overallMark = overallMark; student1.showOverview = showOverview; console.log(student1.showOverview()) student2.overallMark = overallMark; student2.showOverview = showOverview; console.log(student2.showOverview())
Bronnen
MDN web docs, Working with objects